ShowTable of Contents
The purpose of this document is to provide some best practices for developing custom visualizations for both Custom Controls and Native Controls in Domino Designer.
Concept
The main motivation for giving a Custom Control a custom visualization is to aid in the development of applications that use that control.
After all, once a Custom Control has been completed, the details of it construction are largely irrelevant, especially if the controls consumer is not its original developer. They do not affect the operations of the control, only how they appear in XPages and other Custom Controls during development.
Custom visualizations are more of a necessity when developing native controls. Native Controls require a custom visualization, or they will render as unknown controls in the XPages/Custom Controls editor. Giving these controls a custom visualization allows you to control how they render as well as their behavior in the XPages/Custom Controls editor.
Custom Controls
Lets take the example of the ccTagCloud Custom Control within the "Discussion - Notes & Web" template that ships with Domino Designer.
The ccTagCloud Custom Control represents a tag cloud control. As you will see the tag cloud Custom Control is essentially a series of nested panels containing a repeat control that will render a number of link controls inside a span control.
This type of control could clearly be reused in any number of applications and by any number of potential application developers. As well styled as this control may be at runtime, during development, this Custom Control will look nothing like a real tag cloud.
Here is how it would look on an XPage with no custom visualization specified.
To aid any potential developer in utilizing this control, the solution was to simply provide a custom visualization that renders an image of the control running on a server in place of the Custom Controls design as would normally be shown. (Ignore where it says "tagCloud for null" for now. It will be explained later on).
Specifying the Custom visualization
Custom Control custom visualizations are specified in the "Design Definition" properties panel (displayed when editing a Custom Control). The custom markup specified in the Design Definition panel must be valid XSP markup. What this means, is that essentially it must be the complete source of any valid XPage or Custom Control.
Designing the Custom visualization
As previously stated, the markup for the custom visualization must be valid XSP markup. The easiest way to create valid XSP markup is to use the XPages/Custom Control editor. To do this you will need to create a new XPage or Custom Control. For the most part, it is best to create a new Custom Control, especially when working with Native Controls (I will explain why later).
Once you have your temporary Custom Control created, you can use the controls palette to drag and drop controls and create a more user friendly representation of your Custom Control. At this stage, you only need to worry about how it looks and not with whether it would actually work. So for the ccTagCloud Custom Control, we would just need to drop an image on the temporary Custom Control.
When you are happy with the design, switch to the source tab and copy the entire contents of the page.
Switch back to your original Custom Control and paste this into its design definition panel.
Your Custom Control (In this case, the ccTagCloud Custom Control) will now appear with your new user friendly representation across Designer. Like so:
Beyond the basic case
As you might imagine a custom visualization often needs to be more complicated than what can be accomplished using the method above alone. For example if instead of using an image to represent the tagCloud, you may want to build a complete representation of the tagCloud for translation purposes etc.. Here is an example of some XSP source for a Custom Control that will look similar to the tagCloud image.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:panel
style="height:191.0px;width:176.0px;border-color:rgb(255,255,255);background-color:rgb(248,248,248)">
<xp:section id="section1"
style="border-color:rgb(255,255,255)">
      
<xp:span style="font-weight:bold">Top 25 Tags</xp:span>
</xp:section>
<xp:image url="/ccTagClould_slider.JPG" id="image1"
style="width:175.0px">
</xp:image>
<xp:label value="Agenda" id="label1"
style="color:rgb(14,78,112);font-size:10pt;font-weight:bold">
</xp:label>
<xp:label value="Cloud" id="label22"
style="font-size:10pt;color:rgb(14,78,112);font-weight:bold">
</xp:label>
<xp:label value="Communities" id="label2"
style="font-size:9pt;color:rgb(150,209,241);font-weight:bold">
</xp:label>
<xp:label value="Connections" id="label3"
style="font-weight:bold;color:rgb(150,209,241);font-size:9pt">
</xp:label>
<xp:label value="Greeting" id="label4"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="Lotusphere Admin" id="label5"
style="color:rgb(14,78,112);font-size:10pt;font-weight:bold">
</xp:label>
<xp:label value="Lotusphere" id="label6"
style="font-size:12pt;color:rgb(14,78,112);font-weight:bold">
</xp:label>
<xp:label value="Notes" id="label7"
style="color:rgb(150,209,241);font-weight:bold;font-size:9pt">
</xp:label>
<xp:label value="Overlay" id="label8"
style="font-size:9pt;color:rgb(150,209,241);font-weight:bold">
</xp:label>
<xp:label value="Schedule" id="label9"
style="color:rgb(14,78,112);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="Scheduler" id="label10"
style="font-size:10pt;color:rgb(14,78,112);font-weight:bold">
</xp:label>
<xp:label value="Session" id="label11"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="Sessions" id="label12"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="Tag" id="label13"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="help" id="label14"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="iNotes" id="label15"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="iPhone" id="label16"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="issl" id="label17"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="lotus" id="label18"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="solutions" id="label19"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="development" id="label20"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="lab" id="label21"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
</xp:panel>
</xp:view>
Here is how it looks at design time
Scriptlet Tags
You can see that the design above is built using no more than a section control with some text in it, followed by an image for the slider and a series of styled labels for the tags. This works fine, but it is quite tedious having to create all those labels manually. This can be overcome by using embedded JavaScript. The custom visualization framework has a JavaScript preprocessor, which allows JavaScript embedded in the custom markup to be executed before the markup is rendered in the XPages/Custom Control editor. The preprocessor only allows JavaScript to be used, it does not support the use of any Java code.
JavaScript can be embedded by surrounding it with scriptlet tags (<%.....%>). When working with scriplet tags, it is always best to work in the source editor of the temporary Custom Control. If you attempt to add scriptlet tags to the design editor, they will look fine at design time, but are being encoded into the source editor. So <% in the design editor is being turned into <% in the source editor for example. This will not work as custom markup when you copy and paste the source of the temporary Custom Control later on.
What that means for us in this case, is that instead of creating 21 individual labels, we can just create one and wrap it in a JavaScript for loop so that it is repeated 21 times. Like this.
<%for (var x=0;x<21;x++){%>
<xp:label value="Label"id="label23"></xp:label>
<%}%>
Labels are not required to have ids, but many other controls are, and those ids must be unique. And remember, the markup to be visualized must be valid after the JavaScript has been executed. So for many controls, in your custom visualization code, you will have to generate those unique ids yourself. For the most part it is probably best to just use the incrementing variable in the for loop as the id. To accomplish this you can use the expression scriptlet tags (<%=...%>) to add the result of a JavaScript expression to the custom markup. So in this case to add a unique id to all the labels in our visualization we could do this
<%for (var x=0;x<21;x++){%>
<xp:label value="Label"id=<%='Label'+x%>"></xp:label>
<%}%>
As you could clearly see the previous examples did not deal with the cases of each of the labels having a different value or style attribute. But using the same techniques, here is some code that creates a comparable visualization.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:panel
style="height:191.0px;width:176.0px;border-color:rgb(255,255,255);background-color:rgb(248,248,248)">
<xp:section id="section1"
style="border-color:rgb(255,255,255)">
      
<xp:span style="font-weight:bold">Top 25 Tags</xp:span>
</xp:section>
<xp:image url="/ccTagClould_slider.JPG" id="image1"
style="width:175.0px">
</xp:image>
<%
//the array of labels to use
var labelArray = ["Agenda","Cloud","Communities","Connections",
"Greeting","Lotusphere Admin","Lotusphere","Notes","Overlay","Schedule",
"Scheduler","Session","Sessions","Tag","help","iNotes","iPhone","issl",
"lotus","solutions","development","lab"];
//This function will randomly return one of the four styles uses in the visualization
function getRandomStyle(){
var rand = Math.floor(Math.random()*4);
if(rand==0){
return("font-size:9pt;color:rgb(150,209,241);font-weight:bold");
}
if(rand==1){
return("font-size:9pt;color:rgb(14,78,112);font-weight:bold");
}
if(rand==2){
return("font-size:10pt;color:rgb(14,78,112);font-weight:bold");
}
if(rand==3){
return("font-size:12pt;color:rgb(14,78,112);font-weight:bold");
}
}
for (var x=0;x<labelArray.length;x++){%>
<xp:label value="<%=labelArray[x]%>" id="<%='Label'+x%>" style="<%=getRandomStyle()%>"></xp:label>
<%}%>
</xp:panel>
</xp:view>
Note: In Domino Designer v8.5.2 you may get a validation error saying "Invalid control id" when you add this source to the Design Definition panel of a Custom Control.

This is being caused by the computed id for the labels ( id="
<%='Label'+x%>" ). It is safe to ignore these error in this case if you see it. It is being caused by a bug in Designer (SPR# GOKE87ES2J).
At Design time, given this custom markup, the ccTagCloud Custom Control would render like this:
Accessing Custom Properties
The tagCloud control needs to be bound to a view when it is added to an XPage/Custom Control, using the viewName custom property found on the "Custom Properties" property panel for the control ( The viewName custom property is specified in the "Property Definition" property panel for the ccTagCloud Custom Control). So it is possible to have more than one tagCloud on an XPage/Custom Control that are bound to different views. As you can see in the ccTagCloudGroup Custom Control, also from the "Discussion - Notes & Web" template that ships with Domino Designer. For development purposes, it is important to know which view a tagCloud is bound to. To be able to do this, we will need access to the attributes on the ccTagCloud Custom Control. Access to the custom properties on a Custom Control are available using "this." notation.
So for example. In the ccTagCloud custom markup, we could add
<xp:panel>
tagCloud for <%=this.viewName %>
</xp:panel>
We could also use a label control for this, or even <p> tags etc... Giving us a final Custom Markup of
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:panel
style="height:191.0px;width:176.0px;border-color:rgb(255,255,255);background-color:rgb(248,248,248)">
<xp:section id="section1"
style="border-color:rgb(255,255,255)">
      
<xp:span style="font-weight:bold">Top 25 Tags</xp:span>
</xp:section>
<xp:image url="/ccTagClould_slider.JPG" id="image1"
style="width:175.0px">
</xp:image>
<%
//the array of labels to use
var labelArray = ["Agenda","Cloud","Communities","Connections",
"Greeting","Lotusphere Admin","Lotusphere","Notes","Overlay","Schedule",
"Scheduler","Session","Sessions","Tag","help","iNotes","iPhone","issl",
"lotus","solutions","development","lab"];
//This function will randomly return one of the four styles uses in the visualization
function getRandomStyle(){
var rand = Math.floor(Math.random()*4);
if(rand==0){
return("font-size:9pt;color:rgb(150,209,241);font-weight:bold");
}
if(rand==1){
return("font-size:9pt;color:rgb(14,78,112);font-weight:bold");
}
if(rand==2){
return("font-size:10pt;color:rgb(14,78,112);font-weight:bold");
}
if(rand==3){
return("font-size:12pt;color:rgb(14,78,112);font-weight:bold");
}
}
for (var x=0;x<labelArray.length;x++){%>
<xp:label value="<%=labelArray[x]%>" id="<%='Label'+x%>" style="<%=getRandomStyle()%>"></xp:label>
<%}%>
<xp:panel>
tagCloud for <%=this.viewName %>
</xp:panel>
</xp:panel>
</xp:view>
Note: In Domino Designer v8.5.2 you may see a NullPointerException

This is being caused by
<%=this.viewName %>. It is safe to ignore these error in this case if you see it. It is being caused by a bug in Designer (SPR# MKEE86XGY5).
This will display the value of the viewName attribute below the tagCloud visualization. Here is how it would display on an XPage/Custom Control where the ccTagCloud control is bound to a view named view1
Facets, Callbacks and Editable Areas
For Custom Controls that contain "Editable Areas", it is important that we enable users to create custom visualizations that still allow those editable areas to be used.
For those of you unfamiliar with the term, an "Editable Area" is a control that can be placed on a Custom Control that allows users of that Custom Control to contribute their own content to it. It essentially provides a area within a Custom Control that a user can drop a control or other controls to once the Custom Control has been placed on an XPage/Custom Control. The control(s) will render in the location of the Editable Area in the Custom Control. You may see these controls referred to as "Editable Areas", "Callbacks" or "Facets". "Editable Area" is the title given to the control in the Controls Palette. When you drop an "Editable Area" onto a Custom Control, it creates a callback element (xp:callback tag) in the source of the page. A facet is an area within a control that has the ability to render another control inside of it. You may see references to facets unrelated to Custom Controls as some Core/Container Controls also use them. The xp:callback tag represents a facet in a Custom Control. There are two different types of facets. Those that have a facetName and those that don't. The facetName is specified as an attribute on the xp:callback control.
Facets that have a facetName are by far the most common type. They allow one control only to be added to them. A simple example of using a facet is the Data Table control. If you drop a Data Table to an XPage/Custom Control, you will see two columns in the dataTable, each with a header, a body and a footer. The header and the footer are actually facet areas. The header has the facetName "header" and the footer has the facetName "footer". The body is a standard content area, so any controls dropped to the body will simply become children of that column element.
If you add some text to the header, body and footer, will see how the source changes. You should be left with something like this:
<xp:dataTable id="dataTable1" rows="30">
<xp:column id="column1">
I am the body
<xp:this.facets>
<xp:span xp:key="footer">I am a footer</xp:span>
<xp:span xp:key="header">I am a header</xp:span>
</xp:this.facets></xp:column>
<xp:column id="column2"></xp:column>
</xp:dataTable>
It should look like this at design time
Looking at the first column, you can see that the text in the body, is just a child of the column tag. Elements that are to be placed in a facet, must have an xp:key attribute set on them, where the value of the xp:key attribute matches the facetName of the facet it is to appear in. So in this case for the header the xp:key attribute is set to "header" and for the footer it is set to "footer". It does not matter what order the elements are added, provided that their xp:key attribute matches the facetName of the facet, that is where they will appear both at design time and run time. Any control that specifies an xp:key attribute must be wrapped in an <xp:this.facets> tag to tell the parent control that it is being put in a facet.
For Custom Controls, a facet is far more easily recognizable. Take the placeBar Custom Control for example (From the "Discussion - Notes & Web" template that ships with Domino Designer). It contains an "Editable Area" with a facetName of "Buttons". If you add the placeBar Custom Control to an XPage/Custom Control it should render like this:
You can see the facet clearly renders as a green circle with the facetName beside it. An end user can drop any single control to that facet area. Of course, if they chose to drop a container control, like a Panel, they can then add further controls as children of that.
Facets that do not have a facetName specified exist only for Custom Controls and Native Controls (Note: They can only be used for Visualization purposes with Native Controls. xp:callback controls with no facet_name will not be used at runtime for Native Controls). They allow a user to drop multiple controls into them. Controls that will then act as children of that Custom Control/Native Control. So if you were to add two "Editable Areas" to a Custom Control, neither of which had facetNames specified, any control that is later added to one of those facets, would ultimately display in both (The same is true if you had two "Editable Area" controls with the same facetName specified. Anything designated to display in one, would display in both!). Controls added to facets that do not specify a facetName, do not need an xp:key attribute, and as such do not need to be wrapped in a <this.facets> tag. Here is how the placeBar Custom Control would render if it did not have a facetName specified on its callback control.
To enable facets to work with custom visualizations, we allow custom markup to contain callback controls. Provided the custom markup contains a callback control that matches the one from the original Custom Control markup, users should be able to interact with it that same way as if no custom markup was provided. Lets take an example of building a very simple custom visualization for the placeBar Custom Control. Again we start with a temporary Custom Control. Facets are the reason we start from a Custom Control and not an XPage. Editable Areas only appear on the palette when we are editing Custom Controls.
So for the placeBar visualization, we can just drop a label and change it to say "Place Bar Title" and then drop an Editable Area and set its facetName to be Buttons.
You way want to copy and paste the source of the callback control from the actual Custom Control markup to the temporary Custom Control, to be sure it matches exactly. The source should look like this.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:label value="Place Bar Title" id="label1"></xp:label>
<xp:br></xp:br>
<xp:callback facetName="Buttons" id="callback1"></xp:callback>
</xp:view>
Using that markup for the custom visualization of the placeBar Custom Control, it will now display like this at design time
You can see the facet has rendered exactly as it did before and will work in exactly the same way as it did before.
It is very important that the source of the callback controls in the custom visualization match exactly their source in the original Custom Control markup. The custom markup will allow you to add any facetName you wish, or you could add facets that do not have facetNames. Those facets will look and act just like any facet that were really in the Custom Control, but if the xp:key attribute a user adds to an element in the facet does not match the real facetName, or no xp:key attribute is specified, the element the user added will not render at runtime. Similarly, if a user specifies an xp:key attribute on an element and the facet has no facetName, the element will not render at runtime.
Things to remember
-Don't add scriplet tags to the design editor. They will be encoded in the source editor, which is not valid as custom markup.
-Some controls need to have unique ids. Make sure your custom markup will have unique ids after any JavaScript has executed.
-Always ensure the facets in any custom visualization match exactly the facets in the original Custom Control markup. Using facets in Custom Controls rendering that don't exist in the Custom Control can cause embedded control not to render at runtime.
One last caveat
If your Custom Control is going to be used across multiple databases, be sure not to use images that may not be resources in other dbs. Any images that cannot be found will render as an unknown image. Similarly if you are using other Custom Controls or including XPages in a custom visualization, ensure they will be available to all end users as this may break the rendering. Users will see this error if any tags in the custom visualization cannot be resolved (This includes, using tag libraries an end user may not have available to them, or including Custom Controls that a user may not have available to them).
Any included XPage will appear blank if it cannot be resolved.
Native Controls
Almost everything that applied to Custom Controls also applies to Native Controls. The major different is how the custom visualization for an Native Control is specified. There is no Design Definition panel for an Native Control, so the custom markup must be specified in the "Component Definition" for the Control in the xsp-config file for your Control Library.
If you have been working with Native Controls, then for the purposes of this document, we are assuming that you already know how to implement and include a Native Control Library.
See
http://www-10.lotus.com/ldd/ddwiki.nsf/dx/Master_Table_of_Contents_for_XPages_Extensibility_APIs_Developer_Guide
Specifying the Custom visualization
The markup for the custom visualization of an Native Control, needs to be specified with <render-markup> tags in the xsp-config file for your Control Library.
Firstly, you will need to locate the xsp-config file that contains the Component Definition for the Control you would like to add a custom visualization to. Once you have the Component Definition, you will need to add <render-markup></render-markup> tags like this.
<component>
<component-extension>
<designer-extension>
<render-markup></render-markup>
</designer-extension>
</component-extension>
</component>
Lets take the example of a simple custom visualization
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:label value="Label" id="label1"></xp:label>
</xp:view>
You cannot just add this markup as it is to the <render-markup></render-markup> tags, as the tags in the custom visualization would act as child tags of the render markup, invalidating the xsp-config file. The custom markup must be encoded first. All that really means is that all '&' symbols need to be replaced by "&", all '<' symbols need to be replaced by "<" and all '>' symbols need to be replaced by ">". So given the custom markup above, your component definition would need to look like this:
<component>
<component-extension>
<designer-extension>
<render-markup>
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:label value="Label" id="label1"></xp:label>
</xp:view>
</render-markup>
</designer-extension>
</component-extension>
</component>
You could use "Find/Replace All" to generate this from the custom markup, but that can be difficult to maintain and there is an easier way. This is the second reason it is better to use temporary custom controls to build custom visualizations than a temporary XPage or a text file etc... Simply design the temporary custom controls as you would have done before.
Switch to the source tab, copy the entire contents of the page and paste it into the Design Definition property panel.
In the same way that you have a xsp-config file for you Native Control Library, every custom control has to have its own xsp-config file also. Once you save your temporary custom control, the encoded contents of the Design Definition panel are saved into the xsp-config file for that Custom Control. You can copy and paste the <render-markup></render-markup> tags directly out of the temporary custom controls xsp-config file and into your Native Controls Component Definition. The xsp-config files for the custom controls in an Application, do not show up in the Applications Navigator, so you will need to use another view to access them. The easiest view that I've found to use is the General -> Navigator view. To open it, go to Window -> Show Eclipse Views -> Other... and select the General -> Navigator view.
Open the nsf in the General Navigator that contains your custom control, and expand the CustomControls folder. You will find an xsp and xsp-config file for each custom controls in your application. Open the xsp-config file for your temporary custom control. There you will find the <render-markup></render-markup> tags complete with the encoded contents that you added to the Design Definition property panel, ready to be copy and pasted to the Component Definition of your native control.
Using Images in Native Control Visualizations
Normally when we use images on XPages/Custom Controls, those images must be in the Resources/Images folder within the Application. When developing custom visualizations for native controls, that contain images, you cannot expect an end users Application to contain those images.
So for native Controls, we assume any images that are being referenced are coming from within the jar that contain the control. However any images that are referenced from within the jar must be on the classpath. The easiest way to accomplish this is to create an icons folder within the 'src' directory of your native controls plugin and store any images there.
These images can then be easily referenced. For example a custom visualization that just adds an image to the page would have a render-markup like this
<render-markup><?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:image url="/icons/testImage.JPG" id="image1"></xp:image>
</xp:view>
</render-markup>
Things to remember
Be careful of using native controls in custom visualizations that are from other native control libraries. Any end users will have to have access to every control used, or else the visualizations will break. This also holds true for any new controls that are added to the Controls Palette in Designer in future releases. Your native control visualizations will only be compatible with Designer builds that contain those new controls.